package models.overview

import play.api.libs.json._

object Index {

  def apply(name: String, stats: JsValue, shards: JsValue, aliases: JsObject): JsValue = {

    val shardsAllocation = (shards \ "shards").as[JsObject].values.flatMap {
      case JsArray(shards) => shards.map { shard =>
        (shard \ "node").asOpt[String].getOrElse("unassigned") -> shard
      }
      case _ => Nil
    }.groupBy(_._1).mapValues { shards => JsArray(shards.map(_._2).toSeq) }.toSeq

    val numShards = (shards \ "shards").as[JsObject].keys.size
    val numReplicas = (shards \ "shards" \ "0").as[JsArray].value.size - 1

    val special = name.startsWith(".")

    JsObject(Seq(
      "name"                -> JsString(name),
      "closed"              -> JsBoolean(false),
      "special"             -> JsBoolean(special),
      "unhealthy"           -> JsBoolean(unhealthyIndex(shardsAllocation)),
      "doc_count"           -> (stats \ "primaries" \ "docs" \ "count").asOpt[JsNumber].getOrElse(JsNumber(0)),
      "deleted_docs"        -> (stats \ "primaries" \ "docs" \ "deleted").asOpt[JsNumber].getOrElse(JsNumber(0)),
      "size_in_bytes"       -> (stats \ "primaries" \ "store" \ "size_in_bytes").asOpt[JsNumber].getOrElse(JsNumber(0)),
      "total_size_in_bytes" -> (stats \ "total" \ "store" \ "size_in_bytes").asOpt[JsNumber].getOrElse(JsNumber(0)),
      "aliases"             -> JsArray(aliases.keys.map(JsString(_)).toSeq), // 1.4 < does not return aliases obj
      "num_shards"          -> JsNumber(numShards),
      "num_replicas"        -> JsNumber(numReplicas),
      "shards"              -> JsObject(shardsAllocation)
    ))
  }

  private def unhealthyIndex(shardAllocation: Seq[(String, JsArray)]): Boolean =
    shardAllocation.exists {
      case ("unassigned", _)    => true
      case (_, JsArray(shards)) => shards.exists(!_.\("state").as[String].equals("STARTED"))
    }

}
